/*
* Copyright 2013, Arondor
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.arondor.common.reflection.parser.spring;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map.Entry;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.config.BeanDefinitionHolder;
import org.springframework.beans.factory.config.RuntimeBeanReference;
import org.springframework.beans.factory.config.TypedStringValue;
import org.springframework.beans.factory.support.ManagedList;
import org.springframework.beans.factory.support.ManagedMap;
import org.springframework.context.expression.BeanExpressionContextAccessor;
import org.springframework.context.expression.BeanFactoryAccessor;
import org.springframework.context.expression.EnvironmentAccessor;
import org.springframework.context.expression.MapAccessor;
import org.springframework.expression.Expression;
import org.springframework.expression.ExpressionParser;
import org.springframework.expression.spel.standard.SpelExpressionParser;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import com.arondor.common.reflection.api.hash.HashHelper;
import com.arondor.common.reflection.model.config.ElementConfiguration;
import com.arondor.common.reflection.model.config.ListConfiguration;
import com.arondor.common.reflection.model.config.MapConfiguration;
import com.arondor.common.reflection.model.config.ObjectConfiguration;
import com.arondor.common.reflection.model.config.ObjectConfigurationFactory;
import com.arondor.common.reflection.model.config.PrimitiveConfiguration;
import com.arondor.common.reflection.model.config.ReferenceConfiguration;
abstract class BeanPropertyParser
{
private static final Logger LOGGER = Logger.getLogger(BeanPropertyParser.class);
private final HashHelper hashHelper;
private final ObjectConfigurationFactory objectConfigurationFactory;
private boolean enableSPEL = true;
public BeanPropertyParser(HashHelper hashHelper, ObjectConfigurationFactory objectConfigurationFactory)
{
this.hashHelper = hashHelper;
this.objectConfigurationFactory = objectConfigurationFactory;
}
public ElementConfiguration parseProperty(Object value)
{
LOGGER.debug("value : " + value);
if (value instanceof TypedStringValue)
{
TypedStringValue stringValue = (TypedStringValue) value;
if (stringValue.getTargetTypeName() != null)
{
return getEnumObjectConfiguration(stringValue);
}
else
{
PrimitiveConfiguration primitiveConfiguration = objectConfigurationFactory
.createPrimitiveConfiguration();
if (useSPEL(stringValue))
{
ExpressionParser parser = new SpelExpressionParser();
String expAsStringWithToken = stringValue.getValue().trim();
String expAsString = expAsStringWithToken.substring(2, expAsStringWithToken.length() - 1).trim();
LOGGER.trace("This property is a SPEL expression: " + expAsString);
// String regex = "systemProperties\\['([^\\s]+)'\\]";
Expression exp = parser.parseExpression(expAsString);
StandardEvaluationContext sec = null;
if (sec == null)
{
sec = new StandardEvaluationContext();
sec.addPropertyAccessor(new EnvironmentAccessor());
sec.addPropertyAccessor(new BeanExpressionContextAccessor());
sec.addPropertyAccessor(new BeanFactoryAccessor());
sec.addPropertyAccessor(new MapAccessor());
}
primitiveConfiguration.setValue(String.valueOf(exp.getValue()));
}
else
{
LOGGER.trace("This property is NOT a SPEL expression: " + stringValue.getValue());
primitiveConfiguration.setValue(stringValue.getValue());
}
return primitiveConfiguration;
}
}
else if (value instanceof RuntimeBeanReference)
{
RuntimeBeanReference beanReference = (RuntimeBeanReference) value;
ReferenceConfiguration referenceConfiguration = objectConfigurationFactory.createReferenceConfiguration();
referenceConfiguration.setReferenceName(beanReference.getBeanName());
return referenceConfiguration;
}
else if (value instanceof ManagedList<?>)
{
return parseValueList((ManagedList<?>) value);
}
else if (value instanceof ManagedMap<?, ?>)
{
return parseValueMap((ManagedMap<?, ?>) value);
}
else if (value instanceof BeanDefinitionHolder)
{
BeanDefinitionHolder beanDefinitionHolder = (BeanDefinitionHolder) value;
return parseBeanDefinition(beanDefinitionHolder.getBeanDefinition());
}
else
{
throw new UnsupportedOperationException("The type of property value is not suppported : " + value
+ " (class : " + value.getClass().getName() + ")");
}
}
private boolean useSPEL(TypedStringValue stringValue)
{
if (!enableSPEL || stringValue == null || stringValue.getValue() == null)
{
return false;
}
String trimmedValue = stringValue.getValue().trim();
return trimmedValue.startsWith("#{") && trimmedValue.endsWith("}");
}
private ObjectConfiguration getEnumObjectConfiguration(TypedStringValue stringValue)
{
ObjectConfiguration enumObjectConfiguration = objectConfigurationFactory.createObjectConfiguration();
enumObjectConfiguration.setClassName(hashHelper.hashClassName(stringValue.getTargetTypeName()));
enumObjectConfiguration.setConstructorArguments(new ArrayList<ElementConfiguration>());
PrimitiveConfiguration enumFieldConfiguration = objectConfigurationFactory
.createPrimitiveConfiguration(stringValue.getValue());
enumObjectConfiguration.getConstructorArguments().add(enumFieldConfiguration);
return enumObjectConfiguration;
}
private ElementConfiguration parseValueList(ManagedList<?> value)
{
return parseBeanList(value);
}
private ElementConfiguration parseValueMap(ManagedMap<?, ?> value)
{
MapConfiguration mapConfiguration = objectConfigurationFactory.createMapConfiguration();
mapConfiguration.setMapConfiguration(new HashMap<ElementConfiguration, ElementConfiguration>());
for (Entry<?, ?> entry : value.entrySet())
{
LOGGER.debug("entry key=" + entry.getKey() + ", value=" + entry.getValue());
ElementConfiguration keyConfiguration = parseBeanObject(entry.getKey());
ElementConfiguration valueConfiguration = parseBeanObject(entry.getValue());
mapConfiguration.getMapConfiguration().put(keyConfiguration, valueConfiguration);
}
return mapConfiguration;
}
// private ElementConfiguration parseFieldList(ManagedList<?> value)
// {
// @SuppressWarnings("unchecked")
// ManagedList<TypedStringValue> stringValueList =
// (ManagedList<TypedStringValue>) value;
//
// ListConfiguration listConfiguration =
// objectConfigurationFactory.createListConfiguration();
// listConfiguration.setListConfiguration(new
// ArrayList<ElementConfiguration>());
//
// for (TypedStringValue stringValue : stringValueList)
// {
// ElementConfiguration primitiveConfiguration = objectConfigurationFactory
// .createPrimitiveConfiguration(stringValue.getValue());
// listConfiguration.getListConfiguration().add(primitiveConfiguration);
// }
// return listConfiguration;
// }
private ElementConfiguration parseBeanObject(Object item)
{
if (item instanceof TypedStringValue)
{
TypedStringValue stringValue = (TypedStringValue) item;
ElementConfiguration primitiveConfiguration = objectConfigurationFactory
.createPrimitiveConfiguration(stringValue.getValue());
return primitiveConfiguration;
}
else if (item instanceof RuntimeBeanReference)
{
RuntimeBeanReference runtimeBeanReference = (RuntimeBeanReference) item;
// return parseBeanDefinition(runtimeBeanReference.getBeanName());
ReferenceConfiguration reference = objectConfigurationFactory.createReferenceConfiguration();
reference.setReferenceName(runtimeBeanReference.getBeanName());
return reference;
}
else if (item instanceof BeanDefinitionHolder)
{
BeanDefinitionHolder beanDefinitionHolder = (BeanDefinitionHolder) item;
return parseBeanDefinition(beanDefinitionHolder.getBeanDefinition());
}
else
{
throw new IllegalArgumentException("Not supported : item class " + item.getClass().getName());
}
}
private ElementConfiguration parseBeanList(ManagedList<?> managedList)
{
ListConfiguration listConfiguration = objectConfigurationFactory.createListConfiguration();
listConfiguration.setListConfiguration(new ArrayList<ElementConfiguration>());
for (Object item : managedList)
{
ElementConfiguration elementConfiguration = parseBeanObject(item);
listConfiguration.getListConfiguration().add(elementConfiguration);
}
return listConfiguration;
}
public abstract ObjectConfiguration parseBeanDefinition(String beanDefinitionName);
public abstract ObjectConfiguration parseBeanDefinition(BeanDefinition beanDefinition);
public boolean isEnableSPEL()
{
return enableSPEL;
}
public void setEnableSPEL(boolean enableSPEL)
{
this.enableSPEL = enableSPEL;
}
}